
#include "aerFrameBuffer.hpp"
#include <cstring>


namespace aer {


FrameBuffer::FrameBuffer()
    : RenderTarget(),
      m_numTextures(0u),
      m_pSpecialBuffer(NULL)
{
  memset( m_attachments, 0, kAttachmentMax*sizeof(GLenum));
}
  
FrameBuffer::~FrameBuffer()
{
  m_pSpecialBuffer = NULL;
  
  if (m_renderbuffer.isGenerated()) {
    m_renderbuffer.release();
  }
}

 
void FrameBuffer::begin()
{
  AER_ASSERT( (m_numTextures > 0u) && "Framebuffer not initialized" );
  
  bind();
  glDrawBuffers( m_numTextures, m_attachments);
  //glViewport( 0, 0, m_width, m_height);
}

void FrameBuffer::end()
{
  unbind();
}

void FrameBuffer::resize(const U32 width, const U32 height)
{
  m_width = width;
  m_height = height;
  //
  
  if (m_renderbuffer.isGenerated()) {
    m_renderbuffer.resize( m_width, m_height);
  }
}


void FrameBuffer::attachColorBuffer(const Texture *pTexture, GLenum attachment)
{
  AER_ASSERT( pTexture != NULL );
  
  const int attachId = attachment - GL_COLOR_ATTACHMENT0;
  AER_ASSERT( (attachId >= 0u) && (attachId < kAttachmentMax) );//
  
  
  if (0 == m_attachments[attachId]) {
    m_numTextures += 1u;
  }
  
  m_attachments[attachId] = attachment;
  m_pTextures[attachId] = pTexture;
  
  glFramebufferTexture2D( GL_FRAMEBUFFER, attachment, pTexture->getTarget(), 
                                          pTexture->getId(), 0);
}

void FrameBuffer::attachSpecialBuffer(const Texture *pTexture, GLenum attachment)
{
  AER_ASSERT( pTexture != NULL );
  
  bool validity = checkSpecialFormat(pTexture->getInternalFormat(), attachment);
  AER_ASSERT( "invalid texture format for this attachment" && validity );//
  
  m_pSpecialBuffer = pTexture;
  glFramebufferTexture2D( GL_FRAMEBUFFER, attachment, pTexture->getTarget(), 
                                          pTexture->getId(), 0);
}

/*
void FrameBuffer::createRenderBuffer(GLenum attachment)
{
  AER_ASSERT( "RenderBuffer already initialized" && !m_renderbuffer.isGenerated() );
  
  m_renderbuffer.generate();
  //m_renderbuffer.setInternalFormat( internalFormat );
  
  //..
  
  // Attach the render buffer as a logical buffer to the currently bound FBO.
  glFramebufferRenderbuffer( GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_renderbuffer.getId());
}
*/

bool FrameBuffer::checkSpecialFormat(int internalFormat, GLenum attachment)
{
  if (internalFormat == GL_DEPTH_COMPONENT   || 
      internalFormat == GL_DEPTH_COMPONENT16 || 
      internalFormat == GL_DEPTH_COMPONENT24 || 
      internalFormat == GL_DEPTH_COMPONENT32F ) 
  {
    return (attachment == GL_DEPTH_ATTACHMENT);
  }

  if (internalFormat == GL_DEPTH24_STENCIL8)
  {
    return (attachment == GL_DEPTH_STENCIL_ATTACHMENT);
  }
  
  return false;
}

} // aer
